package cn.tedu.tmall.front.mall.config;

import cn.tedu.tmall.common.enumerator.ServiceCode;
import cn.tedu.tmall.common.web.JsonResult;
import cn.tedu.tmall.front.mall.filter.JwtAuthorizationFilter;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;

@Configuration
//打开权限查询
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthorizationFilter jwtAuthorizationFilter;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 允许跨越访问
        http.cors();

        // 调整Session创建策略，改为：不使用Session
        // SessionCreationPolicy.NEVER：从不主动创建Session，但是，如果Session已存在，则会使用它
        // SessionCreationPolicy.STATELESS：保持为“无状态”，具体表现为从不使用Session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //自定义的JWT过滤器添加到Security框架中特定的过滤器之前
        http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

        //处理"在未通过验证的情况下,向需要通过验证的资源发起请求,导致403错误"的问题
        http.exceptionHandling().authenticationEntryPoint((request, response, e) -> {
            //设置编码
            response.setContentType("application/json; charset=utf-8");
            String message = "操作失败，您当前未登录，或登录已过期！";
            JsonResult jsonResult = JsonResult.fail(
                    ServiceCode.ERROR_UNAUTHORIZED, message
            );
            String jsonString = JSON.toJSONString(jsonResult);
            PrintWriter writer = response.getWriter();
            writer.println(jsonString);
        });
        //禁用"防止违造的跨越攻击的防御机制"
        http.csrf().disable();
        //白名单
        // 不在白名单中的请求，必须通过Security框架的认证机制，否则会响应403
        // Security框架的认证机制就是：检查SecurityContext中是否存在有效的Authentication
        String[] urls = {
                "/doc.html",
                "/**/*.css",
                "/**/*.js",
                "/swagger-resources",
                "/v2/api-docs",
                "/favicon.ico",
                "/users/login"
        };

        //请求授权
        http.authorizeRequests() //开始配置请求授权
                .mvcMatchers(urls) //匹配某些请求
                .permitAll() //许可,即不需要通过认证即可访问
                .anyRequest() // 匹配任何请求，实际表现为“除了以上配置过的以外的其它请求”
                .authenticated(); // 需要已经通过认证
    }
}
